package com.scau.hwadee.examination.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.scau.hwadee.examination.constant.CheckStatus;
import com.scau.hwadee.examination.constant.LoginInType;
import com.scau.hwadee.examination.entity.UserInfo;
import com.scau.hwadee.examination.mapper.UserInfoMapper;
import com.scau.hwadee.examination.service.LogInOutService;
import com.scau.hwadee.examination.utils.AuthCodeUtils;
import com.scau.hwadee.examination.utils.SendEmailUtils;
import com.scau.hwadee.examination.utils.UniqueIDGeneratorUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import org.thymeleaf.TemplateEngine;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author YHX
 * @description
 * @date 2019/8/4 16:18
 **/
@Service
public class LogInOutServiceImpl implements LogInOutService {

  @Autowired
  private UserInfoMapper userInfoMapper;

  @Autowired
  private JavaMailSender javaMailSender;

  @Autowired
  private TemplateEngine templateEngine;

  private UniqueIDGeneratorUtils.UUIDUniqueIDGeneratorUtils g = new UniqueIDGeneratorUtils.UUIDUniqueIDGeneratorUtils();

  private static Logger logger = LoggerFactory.getLogger(LogInOutServiceImpl.class);

  private static final String formatString = "yyyy-MM-dd HH:mm:ss";


  //userMessage->session
  private static Map<String, Session> userSessionMap = new HashMap<>();

  @Override
  public Map<String, Object> validateVCode(String vcode, Session session) {
    logger.debug("验证验证码");
    Map<String, Object> map = new HashMap<>();
    String code = session.getAttribute("authcode").toString();
    if (vcode.equals(code)) {
      map.put("status", CheckStatus.CORRECT.getCode());
      map.put("message", "验证码正确");
      logger.debug("验证码正确");
    } else {
      map.put("status", CheckStatus.ERROR.getCode());
      map.put("message", "验证码不正确,请重新输入");
      logger.debug("验证码不正确,请重新输入");
    }
    return map;
  }

  @Override
  public void getAuthCode(Session session, HttpServletResponse response) {
    logger.debug("获取验证码");
    /**
     * 设置相应类型，告诉浏览器输出的内容为图片
     */
    response.setContentType("image/jpeg");
    /**
     * 设置响应头信息，告诉浏览器不要缓存此内容
     */
    response.setHeader("Pragma", "No-cache");
    response.setHeader("Cache-Control", "No-cache");
    response.setDateHeader("Expires", 0);
    try {
      ImageIO.write(AuthCodeUtils.createImage(), "JPEG", response.getOutputStream());
      String rand = AuthCodeUtils.getsRand();
      /**
       * 将验证码存到session中
       */
      session.setAttribute("authcode", rand);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Override
  public String register(UserInfo userInfo) {
    logger.debug("用户注册");
    String message = validateUser(userInfo);
    try {
      if ("新用户".equals(message)) {
        if (userInfo.getUserPK() == null) {
          userInfo.setUserPK(g.generatorId());
        }
        if (userInfo.getUserRegTime() == null) {
          userInfo.setUserRegTime(new Date());
        }
        if (userInfo.getUserType() == null) {
          userInfo.setUserType(1);
        }
        String userMessage = userInfo.getUserName() +
          userInfo.getUserTelephone() +
          userInfo.getUserEmail();
        userInfo.setUserPassword(new SimpleHash("MD5", userInfo.getUserPassword(), userMessage, 1024).toString());
        int cnt = userInfoMapper.addUser(userInfo);
        System.out.println("----" + cnt + "----");
        if (cnt > 0) {
          logger.debug("注册成功");
          Map<String, Object> map = new HashMap<>(10);
          map.put("html", "welcome.html");
          map.put("name", userInfo.getUserName());
          map.put("userEmail", userInfo.getUserEmail());
          email(map);
          return "注册成功";
        } else {
          logger.debug("注册失败");
          return "注册失败";
        }
      } else {
        logger.debug(message);
        return message;
      }
    } catch (Exception e) {
      logger.debug("注册失败", e);
      return "注册失败";
    }
  }

  private String validateUser(UserInfo userInfo) {
    logger.debug("验证用户是否合法");
    String userName = userInfo.getUserName();
    String userEmail = userInfo.getUserEmail();
    String userTelephone = userInfo.getUserTelephone();
    if (userInfoMapper.getUserCountByUserName(userName) > 0) {
      logger.debug("注册失败，用户名已经存在，请重新输入！！");
      return "用户名已经存在，请重新输入！！";
    }
    if (userInfoMapper.getUserCountByUserEmail(userEmail) > 0) {
      logger.debug("注册失败，用户邮箱已经存在，请重新输入！！");
      return "用户邮箱已经存在，请重新输入！！";
    }
    if (userInfoMapper.getUserCountByUserTelephone(userTelephone) > 0) {
      logger.debug("注册失败，用户电话号码已经存在，请重新输入！！");
      return "用户电话号码已经存在，请重新输入！！";
    }
    return "新用户";
  }


  @Override
  public Map<String, Object> checkLogInStatus(Session session) {
    logger.debug("检查登录状态");
    Map<String, Object> map = new HashMap<>();
    if (session.getAttribute("UserType") != null) {
      String userType = session.getAttribute("UserType").toString();
      map.put("UserType", userType);
    }
    return map;
  }

  @Override
  public int checkLoginType(String message, Session session) {
    /**
     * 相同浏览器登录
     */
    if (session.getAttribute("userMessage") != null) {
      return LoginInType.SAMEBROWSERREPEATLOGIN.getCode();
    }
    /**
     * 不同浏览器登录
     */
    else if (userSessionMap.containsKey(message)) {
      userSessionMap.remove(message);
      userSessionMap.put(message, session);
      return LoginInType.DIFFERENTBROWSERREPEATLOGIN.getCode();
    }
    /**
     * 正常登录
     */
    else {
      userSessionMap.put(message, session);
      return LoginInType.NORMALLOGIN.getCode();
    }
  }

  @Override
  public Map<String, Object> login(@RequestBody Map<String, Object> param) {
    logger.debug("用户登录");
    logger.debug("前端传过来的参数,param={}", param);
    Subject subject = SecurityUtils.getSubject();
    Session session = subject.getSession();
    String vCode = param.get("vCode").toString();
    Map<String, Object> vMap = validateVCode(vCode, session);
    Map<String, Object> map = new HashMap<>();
    if ((int) vMap.get("status") == CheckStatus.ERROR.getCode()) {
      map.put("isCorrect", false);
      map.put("reLogin", false);
      map.put("message", "验证码错误");
      return map;
    }
    String userMessage = param.get("userName").toString()
      + param.get("userEmail").toString()
      + param.get("userTelephone").toString();
    UsernamePasswordToken upToken = new UsernamePasswordToken(userMessage, param.get("userPassword").toString());
    String message = null;
    try {
      subject.login(upToken);
      UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
      int userType = userInfo.getUserType();
      message = userInfo.getUserName() + userInfo.getUserTelephone() + userInfo.getUserEmail();
      logger.debug("从数据库读出来的用户信息为：{}", JSON.toJSONStringWithDateFormat(userInfo, formatString, SerializerFeature.WriteDateUseDateFormat));
      map.put("userName", userInfo.getUserName());
      map.put("userInfo", userInfo);
      int loginType = checkLoginType(message, session);
      if (loginType == LoginInType.SAMEBROWSERREPEATLOGIN.getCode()) {
        logger.debug("用户在相同浏览器重复登录");
        map.put("isCorrect", false);
        map.put("reLogin", true);
        return map;
      } else if (loginType == LoginInType.DIFFERENTBROWSERREPEATLOGIN.getCode()) {
        logger.debug("用户在不同浏览器重复登录");
        map.put("reLogin", true);
      } else {
        logger.debug("用户正常登录");
        map.put("reLogin", false);
      }
      map.put("isCorrect", true);
      if (userType == 1) {
        map.put("UserType", "公众");
      } else if (userType == 2) {
        map.put("UserType", "主考院校");
      } else if (userType == 3) {
        map.put("UserType", "计划科");
      } else {
        map.put("UserType", "考务岗");
      }
    } catch (Exception e) {
      map.put("isCorrect", false);
      map.put("reLogin", false);
      logger.debug("错误为: ", e);
    }
    if ((boolean) map.get("isCorrect")) {
      session.setAttribute("userType", map.get("userType"));
      session.setAttribute("userInfo", map.get("userInfo"));
      session.setAttribute("userMessage", message);
    }
    return map;
  }

  @Override
  public String logout() {
    logger.debug("用户登出");
    Subject subject = SecurityUtils.getSubject();
    try {
      subject.logout();//当subject调用logout方法的时候会自动调用session的stop方法
      return "登出成功";
    } catch (Exception e) {
      logger.debug("错误为：", e);
      return "登出失败";
    }

  }

  @Override
  public Map<String, Object> email(Map<String, Object> map) {
    Map<String, Object> result = new HashMap<>();
    String emailAuthCode = createRandomAuthCode(6);
    map.put("emailAuthCode", emailAuthCode);
    SendEmailUtils sendEmail = new SendEmailUtils(javaMailSender, templateEngine, map);
    new Thread(sendEmail).start();
    logger.debug("生成的邮箱验证码为：{}", emailAuthCode);
    result.put("emailAuthCode", emailAuthCode);
    return result;
  }

  @Override
  public String createRandomAuthCode(int bits) {
    StringBuffer sb = new StringBuffer();
    Random random = new Random();
    while (bits-- != 0) {
      sb.append(random.nextInt(10));
    }
    return sb.toString();
  }
}
